﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using TCC.CMFlow.Models;
using TCC.CMFlow.Contexts;
using TCC.WSClient;
using System.Reflection;
using System.Collections;
using System.Web.Script.Serialization;
using TCC.CMFlow.Business;
using Microsoft.AspNet.Identity;
using TCC.CMFlow.Models.Enumerators;
using TCC.CMFlow.Properties;

namespace TCC.CMFlow.Controllers
{
    [Authorize]
    public class CategoriaWorkflowController : Controller
    {
        private DataContext db = new DataContext();

        // GET: /CategoriaWorkflow/
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow)]
        public ActionResult Index()
        {
            var grupos = db.GrupoAprovacao.Where(GrupoAprovacao.IsAtivoExpression).ToList();
            ViewBag.CategoriaGrupo = new SelectList(grupos, "ID", "Nome");

            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.CategoriaGrupoUsuario = new SelectList(usuarios, "Id", "Nome");

            return View(db.CategoriaWorkflow.ToList());
        }

        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Consultar)]
        public ActionResult Search(string ID, string nome, string CategoriaGrupo, string CategoriaGrupoUsuario)
        {
            long _ID;
            long.TryParse(ID, out _ID);

            long _IDGrupo;
            long.TryParse(CategoriaGrupo, out _IDGrupo);

            var grupos = db.GrupoAprovacao.Where(GrupoAprovacao.IsAtivoExpression).ToList();
            ViewBag.CategoriaGrupo = new SelectList(grupos, "ID", "Nome", CategoriaGrupo);

            var usuarios = db.Users.Where(Usuario.IsAtivoExpression).ToList();
            ViewBag.CategoriaGrupoUsuario = new SelectList(usuarios, "Id", "Nome");

            var categorias = from c in db.CategoriaWorkflow
                             select c;

            if (_ID > 0)
            {
                categorias = categorias.Where(g => g.ID == _ID);
            }

            if (!String.IsNullOrEmpty(nome))
            {
                categorias = categorias.Where(g => g.Nome.ToUpper().Contains(nome.ToUpper()));
            }

            if (_IDGrupo > 0)
            {
                categorias = categorias.Where(c => c.CategoriaGrupos.Any(g => g.GrupoAprovacao.ID == _IDGrupo));
            }

            if (!string.IsNullOrEmpty(CategoriaGrupoUsuario))
            {
                categorias = categorias.Where(c => c.CategoriaGrupos.Any(g => g.Usuarios.Any(u => u.Id == CategoriaGrupoUsuario)));
            }

            return View("Index", categorias.ToList());
        }

        // GET: /CategoriaWorkflow/Details/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Visualizar)]
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            if (categoriaworkflow.CategoriaWebService == null)
            {
                categoriaworkflow.CategoriaWebService = new CategoriaWebService();
                db.Entry(categoriaworkflow).Reload();
            }

            return View(categoriaworkflow);
        }

        // GET: /CategoriaWorkflow/Create
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Incluir, isModal = true)]
        public ActionResult Create()
        {
            return PartialView();
        }

        // POST: /CategoriaWorkflow/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include="ID,Nome,Descricao,InicioVigencia,FimVigencia")] CategoriaWorkflow categoriaworkflow)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    db.CategoriaWorkflow.Add(categoriaworkflow);
                    db.SaveChanges();

                    Logger.AddLog(EnumTipoLog.Incluido, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaIncluida, categoriaworkflow.ID, categoriaworkflow.Nome));

                    return Json(new { success = true });
                }

                return PartialView(categoriaworkflow);
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/Edit/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }
            return PartialView(categoriaworkflow);
        }

        // POST: /CategoriaWorkflow/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include="ID,Nome,Descricao,InicioVigencia,FimVigencia")] CategoriaWorkflow categoriaworkflow)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    db.Entry(categoriaworkflow).State = EntityState.Modified;
                    db.SaveChanges();

                    Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaIncluida, categoriaworkflow.ID, categoriaworkflow.Nome));

                    return Json(new { success = true });
                }

                return PartialView(categoriaworkflow);
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/AdicionarGrupo/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult AdicionarGrupo(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            var grupos = RetornaGruposNaoAdicionados(categoriaworkflow.CategoriaGrupos.Select(g => g.GrupoAprovacao).ToList());
            ViewBag.CategoriaGrupos = new MultiSelectList(grupos, "ID", "Nome");

            return PartialView(categoriaworkflow);
        }

        // POST: /CategoriaWorkflow/AdicionarGrupo/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult AdicionarGrupo(int? id, int[] CategoriaGruposList)
        {
            try
            {
                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
                if (categoriaworkflow == null)
                {
                    return HttpNotFound();
                }

                if (CategoriaGruposList == null)
                {
                    ModelState.AddModelError("Grupo", "Nenhum Grupo foi selecionado.");

                    var usuarios = RetornaGruposNaoAdicionados(categoriaworkflow.CategoriaGrupos.Select(g => g.GrupoAprovacao).ToList());
                    ViewBag.CategoriaGrupos = new MultiSelectList(usuarios, "ID", "Nome");

                    return PartialView(categoriaworkflow);
                }

                var gruposSelecionados = (from p in db.GrupoAprovacao
                                          where CategoriaGruposList.Contains(p.ID)
                                          select p).ToList();

                gruposSelecionados.ForEach(u => categoriaworkflow.CategoriaGrupos.Add(
                    new CategoriaGrupo { CategoriaWorkflow = categoriaworkflow, GrupoAprovacao = u, sequenciaAprovacao = gruposSelecionados.IndexOf(u) + 1 })
                );
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaGruposAdicionados, categoriaworkflow.ID, categoriaworkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/OrdenarGrupo/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult OrdenarGrupo(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            var grupos = categoriaworkflow.CategoriaGrupos
                        .OrderBy(o => o.sequenciaAprovacao)
                        .Select(g => g.GrupoAprovacao);

            return PartialView(grupos);
        }

        // POST: /CategoriaWorkflow/OrdenarGrupo/5
        [HttpPost]
        public JsonResult OrdenarGrupo(int id, List<string> items)
        {
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            categoriaworkflow.CategoriaGrupos.ToList()
                             .ForEach(u => u.sequenciaAprovacao = items.IndexOf(u.GrupoAprovacaoID.ToString()) + 1);
            db.SaveChanges();

            return Json(new { success = true });
        }

        // GET: /CategoriaWorkflow/AssociarUsuario/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult AssociarUsuario(int? categoriaWorkflowID, int? grupoAprovacaoID)
        {
            if (categoriaWorkflowID == null || grupoAprovacaoID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            var categoriagrupo = db.CategoriaWorkflow
                                .SelectMany(c => c.CategoriaGrupos)
                                .Where(g => g.CategoriaWorkflowID == categoriaWorkflowID && 
                                            g.GrupoAprovacaoID == grupoAprovacaoID)
                                .FirstOrDefault();

            if (categoriagrupo == null)
            {
                return HttpNotFound();
            }

            var usuarios = RetornaUsuariosNaoAdicionados(categoriagrupo.GrupoAprovacao.Usuarios, categoriagrupo.Usuarios);
            ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

            return PartialView(categoriagrupo);
        }

        // POST: /CategoriaWorkflow/AdicionarUsuario/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult AssociarUsuario(int categoriaWorkflowID, int grupoAprovacaoID, string[] GrupoUsuariosList)
        {
            try
            {
                var categoriagrupo = db.CategoriaWorkflow
                                .SelectMany(c => c.CategoriaGrupos)
                                .Where(g => g.CategoriaWorkflowID == categoriaWorkflowID &&
                                            g.GrupoAprovacaoID == grupoAprovacaoID)
                                .FirstOrDefault();
                if (categoriagrupo == null)
                {
                    return HttpNotFound();
                }

                if (GrupoUsuariosList == null)
                {
                    ModelState.AddModelError("User", "Nenhum Usuário foi selecionado.");

                    var usuarios = RetornaUsuariosNaoAdicionados(categoriagrupo.GrupoAprovacao.Usuarios, categoriagrupo.Usuarios);
                    ViewBag.GrupoUsuarios = new MultiSelectList(usuarios, "Id", "Nome");

                    return PartialView(categoriagrupo);
                }

                var usuariosSelecionados = (from p in db.Users
                                            where GrupoUsuariosList.Contains(p.Id)
                                            select p).ToList();
                usuariosSelecionados.ForEach(u => categoriagrupo.Usuarios.Add(u));
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaGrupoUsuariosAssociados, categoriagrupo.CategoriaWorkflow.ID, categoriagrupo.CategoriaWorkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/RemoverGrupo/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult RemoverGrupo(int? categoriaWorkflowID, int? grupoAprovacaoID)
        {
            if (categoriaWorkflowID == null || grupoAprovacaoID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            var categoriaGrupo = categoriaworkflow.CategoriaGrupos
                                .Where(g => g.GrupoAprovacaoID == grupoAprovacaoID)
                                .FirstOrDefault();
            if(categoriaGrupo == null)
            {
                return HttpNotFound();
            }

            return PartialView(categoriaGrupo);
        }

        // POST: /CategoriaWorkflow/RemoverGrupo/5
        [HttpPost, ActionName("RemoverGrupo")]
        [ValidateAntiForgeryToken]
        public ActionResult RemoverGrupoConfirmado(int categoriaWorkflowID, int grupoAprovacaoID)
        {
            try
            {
                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
                var categoriaGrupo = categoriaworkflow.CategoriaGrupos
                                    .Where(g => g.GrupoAprovacaoID == grupoAprovacaoID)
                                    .FirstOrDefault();

                categoriaworkflow.CategoriaGrupos.Remove(categoriaGrupo);
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaGruposRemovidos, categoriaworkflow.ID, categoriaworkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/RemoverUsuario/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult RemoverUsuario(int? categoriaWorkflowID, int? grupoAprovacaoID, string usuarioId)
        {
            if (categoriaWorkflowID == null || grupoAprovacaoID == null || usuarioId == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            var categoriaGrupo = categoriaworkflow.CategoriaGrupos
                                .Where(g => g.GrupoAprovacaoID == grupoAprovacaoID)
                                .FirstOrDefault();
            if (categoriaGrupo == null)
            {
                return HttpNotFound();
            }

            var usuario = categoriaGrupo.Usuarios
                          .Where(u => u.Id == usuarioId)
                          .FirstOrDefault();
            if (usuario == null)
            {
                return HttpNotFound();
            }

            return PartialView(usuario);
        }

        // POST: /CategoriaWorkflow/RemoverUsuario/5
        [HttpPost, ActionName("RemoverUsuario")]
        [ValidateAntiForgeryToken]
        public ActionResult RemoverUsuarioConfirmado(int categoriaWorkflowID, int grupoAprovacaoID, string usuarioId)
        {
            try
            {
                var categoriagrupo = db.CategoriaWorkflow
                                 .SelectMany(c => c.CategoriaGrupos)
                                 .Where(g => g.CategoriaWorkflowID == categoriaWorkflowID &&
                                             g.GrupoAprovacaoID == grupoAprovacaoID)
                                 .FirstOrDefault();
                var usuario = categoriagrupo.Usuarios
                              .Where(u => u.Id == usuarioId)
                              .FirstOrDefault();

                categoriagrupo.Usuarios.Remove(usuario);
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaGrupoUsuariosRemovidos, categoriagrupo.CategoriaWorkflow.ID, categoriagrupo.CategoriaWorkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);
                
                throw ex;
            }   
        }

        // GET: /CategoriaWorkflow/Delete/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Excluir, isModal = true)]
        public ActionResult Inactivate(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }
            return PartialView(categoriaworkflow);
        }

        // POST: /CategoriaWorkflow/Inactivate/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Inactivate(int id, DateTime? FimVigencia)
        {
            try
            {
                if (FimVigencia < DateTime.Today)
                {
                    ModelState.AddModelError("Date", "O fim da vigência não pode ser retroativo.");
                    return PartialView();
                }

                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
                if (categoriaworkflow.InicioVigencia > FimVigencia)
                {
                    ModelState.AddModelError("Date", "Data fim não pode ser menor que a data início.");
                    return PartialView();
                }

                if (ModelState.IsValid)
                {
                    categoriaworkflow.FimVigencia = FimVigencia;

                    db.Entry(categoriaworkflow).State = EntityState.Modified;
                    db.SaveChanges();

                    Logger.AddLog(EnumTipoLog.Inativado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Empty);

                    return Json(new { success = true });
                }

                return PartialView(categoriaworkflow);
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/ConfigurarWebServiceUri/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult ConfigurarWebServiceUri(int? categoriaWorkflowID)
        {
            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            return PartialView(categoriaworkflow.CategoriaWebService);
        }

        // POST: /CategoriaWorkflow/ConfigurarWebServiceUri/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ConfigurarWebServiceUri(int categoriaWorkflowID, string webServiceUri)
        {
            try
            {
                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
                if (categoriaworkflow == null)
                {
                    return HttpNotFound();
                }

                if (categoriaworkflow.CategoriaWebService == null)
                {
                    categoriaworkflow.CategoriaWebService = new CategoriaWebService();
                }

                Uri _webServiceUri;
                if (!Uri.TryCreate(webServiceUri, UriKind.Absolute, out _webServiceUri))
                {
                    ModelState.AddModelError("Uri", "Uri inválida!");
                    return PartialView(categoriaworkflow.CategoriaWebService);
                }

                categoriaworkflow.CategoriaWebService.WebServiceUri = _webServiceUri.ToString();
                db.Entry(categoriaworkflow).State = EntityState.Modified;
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaWebServiceConfig, categoriaworkflow.ID, categoriaworkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);
                
                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/ConfigurarWebServiceUri/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult ConfigurarWebServiceServico(int? categoriaWorkflowID)
        {
            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            try
            {
                WebServiceInvoker ws = new WebServiceInvoker(new Uri(categoriaworkflow.CategoriaWebService.WebServiceUri));
                ViewBag.Servicos = new SelectList(ws.AvailableContracts);
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("WebService", ex.Message);
                ViewBag.Servicos = new SelectList(new List<string>());
            }

            return PartialView(categoriaworkflow.CategoriaWebService);
        }

        // POST: /CategoriaWorkflow/ConfigurarWebServiceUri/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ConfigurarWebServiceServico(int categoriaWorkflowID, string ServicoNome)
        {
            try
            {
                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
                if (categoriaworkflow == null)
                {
                    return HttpNotFound();
                }

                if (categoriaworkflow.CategoriaWebService == null)
                {
                    categoriaworkflow.CategoriaWebService = new CategoriaWebService();
                }

                categoriaworkflow.CategoriaWebService.ServicoNome = ServicoNome.ToString();
                db.Entry(categoriaworkflow).State = EntityState.Modified;
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaWebServiceConfig, categoriaworkflow.ID, categoriaworkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/ConfigurarWebServiceOperacao/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult ConfigurarWebServiceOperacao(int? categoriaWorkflowID)
        {
            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            try
            {
                WebServiceInvoker ws = new WebServiceInvoker(new Uri(categoriaworkflow.CategoriaWebService.WebServiceUri));
                ViewBag.Operacoes = new SelectList(ws.EnumerateServiceMethods(categoriaworkflow.CategoriaWebService.ServicoNome));
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("WebService", ex.Message);
                ViewBag.Operacoes = new SelectList(new List<string>());
            }

            return PartialView(categoriaworkflow.CategoriaWebService);
        }

        // POST: /CategoriaWorkflow/ConfigurarWebServiceOperacao/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ConfigurarWebServiceOperacao(int categoriaWorkflowID, string OperacaoNome)
        {
            try
            {
                CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
                if (categoriaworkflow == null)
                {
                    return HttpNotFound();
                }

                if (categoriaworkflow.CategoriaWebService == null)
                {
                    categoriaworkflow.CategoriaWebService = new CategoriaWebService();
                }

                categoriaworkflow.CategoriaWebService.OperacaoNome = OperacaoNome.ToString();
                db.Entry(categoriaworkflow).State = EntityState.Modified;
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaWebServiceConfig, categoriaworkflow.ID, categoriaworkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/ConfigurarWebServiceOperacao/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult ConfigurarWebServiceAtributos(int? categoriaWorkflowID)
        {
            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }

            WebServiceInvoker ws = new WebServiceInvoker(new Uri(categoriaworkflow.CategoriaWebService.WebServiceUri));
            var metadata = ws.InvokeMethod<object>(categoriaworkflow.CategoriaWebService.ServicoNome, categoriaworkflow.CategoriaWebService.OperacaoNome);

            long atributoID = 0;
            var lstProp = this.GetWebServiceAtributos(metadata, ref atributoID, null);

            TempData["PropriedadesWS"] = lstProp;
            TempData["categoriaWorkflowID"] = categoriaWorkflowID;

            var recursiveObjects = FillRecursive(lstProp);
            string myjsonmodel = new JavaScriptSerializer().Serialize(recursiveObjects);

            return PartialView("ConfigurarWebServiceAtributos", myjsonmodel);
        }

        // POST: /CategoriaWorkflow/ConfigurarWebServiceAtributos/5
        [HttpPost]
        public ActionResult ConfigurarWebServiceAtributos(int categoriaWorkflowID, FormCollection form)
        {
            try
            {
                CategoriaWebService categoriaWebService = db.CategoriaWebService.Find(categoriaWorkflowID);
                if (categoriaWebService == null)
                {
                    return HttpNotFound();
                }

                List<string> idsSelecionados = new List<string>();
                foreach (var key in form.AllKeys)
                {
                    idsSelecionados.Add(form[key]);
                }

                var propriedadesWebService = TempData["PropriedadesWS"] as List<CategoriaWebServiceAtributo>;
                var propriedadesExistentes = categoriaWebService.CategoriaWebServiceAtributos.ToList();
                var propriedadesSelecionadas = RetornaPropriedadesSelecionadas(propriedadesWebService, propriedadesExistentes, idsSelecionados, categoriaWorkflowID);

                categoriaWebService.CategoriaWebServiceAtributos = propriedadesSelecionadas;
                db.Entry(categoriaWebService).State = EntityState.Modified;
                db.SaveChanges();

                Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaWebServiceConfig, categoriaWebService.CategoriaWorkflow.ID, categoriaWebService.CategoriaWorkflow.Nome));

                return Json(new { success = true });
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/AtribuirApelidoAtributo/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult AtribuirApelidoAtributo(int? atributoID, int? categoriaWorkflowID)
        {
            if (atributoID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWebServiceAtributo categoriaWebServiceAtributo = db.CategoriaWebServiceAtributos.Find(atributoID, categoriaWorkflowID);
            if (categoriaWebServiceAtributo == null)
            {
                return HttpNotFound();
            }

            return PartialView(categoriaWebServiceAtributo);
        }

        // POST: /CategoriaWorkflow/AtribuirApelidoAtributo/5
        [HttpPost]
        public ActionResult AtribuirApelidoAtributo(int atributoID, int categoriaWorkflowID, string apelido)
        {
            CategoriaWebServiceAtributo categoriaWebServiceAtributo = db.CategoriaWebServiceAtributos.Find(atributoID, categoriaWorkflowID);
            if (categoriaWebServiceAtributo == null)
            {
                return HttpNotFound();
            }

            if (ModelState.IsValid)
            {
                categoriaWebServiceAtributo.Apelido = apelido;
                db.Entry(categoriaWebServiceAtributo).State = EntityState.Modified;
                db.SaveChanges();

                return Json(new { success = true });
            }

            return PartialView();
        }

        // GET: /CategoriaWorkflow/AtribuirApelidoAtributo/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Editar, isModal = true)]
        public ActionResult ConfigurarAtributo(int? atributoID, int? categoriaWorkflowID)
        {
            if (atributoID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            if (categoriaWorkflowID == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            CategoriaWebServiceAtributo categoriaWebServiceAtributo = db.CategoriaWebServiceAtributos.Find(atributoID, categoriaWorkflowID);
            if (categoriaWebServiceAtributo == null)
            {
                return HttpNotFound();
            }

            List<int> listaOrdem = new List<int>();
            int qtdAtributos = 0;

            if (categoriaWebServiceAtributo.Parent != null && categoriaWebServiceAtributo.Parent.Childrens != null)
            {
                qtdAtributos = categoriaWebServiceAtributo.Parent.Childrens.Count();
            }

            for (int i = 1; i <= qtdAtributos; i++)
            {
                listaOrdem.Add(i);
            }

            ViewBag.ListaOrdem = new SelectList(listaOrdem, categoriaWebServiceAtributo.Ordem);

            return PartialView(categoriaWebServiceAtributo);
        }

        // POST: /CategoriaWorkflow/AtribuirApelidoAtributo/5
        [HttpPost]
        public ActionResult ConfigurarAtributo(int atributoID, int categoriaWorkflowID, string apelido, int? ordemAtributo, bool isPrimaryKey)
        {
            try
            {
                CategoriaWebServiceAtributo categoriaWebServiceAtributo = db.CategoriaWebServiceAtributos.Find(atributoID, categoriaWorkflowID);
                if (categoriaWebServiceAtributo == null)
                {
                    return HttpNotFound();
                }

                if (ModelState.IsValid)
                {
                    categoriaWebServiceAtributo.Apelido = apelido;
                    categoriaWebServiceAtributo.Ordem = ordemAtributo;
                    categoriaWebServiceAtributo.IsPrimaryKey = isPrimaryKey;
                    db.Entry(categoriaWebServiceAtributo).State = EntityState.Modified;
                    db.SaveChanges();

                    Logger.AddLog(EnumTipoLog.Alterado, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), string.Format(Resources.LogCategoriaWebServiceConfig, categoriaWebServiceAtributo.CategoriaWebService.CategoriaWorkflow.ID, categoriaWebServiceAtributo.CategoriaWebService.CategoriaWorkflow.Nome));

                    return Json(new { success = true });
                }

                return PartialView(categoriaWebServiceAtributo);
            }
            catch (Exception ex)
            {
                Logger.AddLog(EnumTipoLog.Erro, (int)eModulosSistema.CategoriasWorkflow, this.User.Identity.GetUserId(), ex.Message);

                throw ex;
            }
        }

        // GET: /CategoriaWorkflow/Delete/5
        [AuthorizeUserAttribute(Modulo = eModulosSistema.CategoriasWorkflow, Permissao = ePermissoes.Excluir, isModal = true)]
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            if (categoriaworkflow == null)
            {
                return HttpNotFound();
            }
            return View(categoriaworkflow);
        }

        // POST: /CategoriaWorkflow/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(id);
            db.CategoriaWorkflow.Remove(categoriaworkflow);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }

        private List<GrupoAprovacao> RetornaGruposNaoAdicionados(ICollection<GrupoAprovacao> gruposAdicionados)
        {
            var gruposAtivos = db.GrupoAprovacao.Where(GrupoAprovacao.IsAtivoExpression).ToList();
            var grupos = gruposAtivos.Except(gruposAdicionados, new LambdaComparer<GrupoAprovacao>((a, b) => a.ID == b.ID, a => (int)a.ID)).ToList();

            return grupos;
        }

        private List<Usuario> RetornaUsuariosNaoAdicionados(ICollection<Usuario> usuariosGrupo, ICollection<Usuario> usuariosAdicionados)
        {
            var usuarios = usuariosGrupo.Except(usuariosAdicionados, new LambdaComparer<Usuario>((a, b) => a.Codigo == b.Codigo, a => (int)a.Codigo)).ToList();

            return usuarios;
        }

        private List<CategoriaWebServiceAtributo> GetWebServiceAtributos(object metadata, ref long atributoID, long? parentID)
        {
            List<CategoriaWebServiceAtributo> listaPropriedadeWS = new List<CategoriaWebServiceAtributo>();

            if (metadata == null)
            {
                return listaPropriedadeWS;
            }

            object myobject;
            if (metadata.GetType().IsArray)
            {
                var myarray = metadata as Array;
                myobject = myarray.GetValue(0);

                atributoID++;

                CategoriaWebServiceAtributo propriedadeWS = new CategoriaWebServiceAtributo();
                propriedadeWS.ID = atributoID;
                propriedadeWS.ParentID = parentID;
                propriedadeWS.Nome = myobject.GetType().Name;
                propriedadeWS.Childrens = GetWebServiceAtributos(myobject, ref atributoID, atributoID);

                listaPropriedadeWS.Add(propriedadeWS);

                return listaPropriedadeWS;
            }
            else
            {
                myobject = metadata;
            }

            Type theType = myobject.GetType();
            List<PropertyInfo> propriedadesMetadata = theType.GetProperties()
                .Where(p => p.Name != "ExtensionData" &&
                            p.DeclaringType == theType)
                .ToList();

            foreach (PropertyInfo prop in propriedadesMetadata)
            {
                atributoID++;

                CategoriaWebServiceAtributo propWS = new CategoriaWebServiceAtributo();
                propWS.ID = atributoID;
                propWS.ParentID = parentID;
                propWS.Nome = prop.Name;

                if (prop.PropertyType.Assembly == theType.Assembly)
                {
                    object propValue = prop.GetValue(myobject, null);
                    propWS.Childrens = GetWebServiceAtributos(propValue, ref atributoID, atributoID);
                }

                listaPropriedadeWS.Add(propWS);
            }

            return listaPropriedadeWS;
        }

        private List<RecursiveObject> FillRecursive(List<CategoriaWebServiceAtributo> flatObjects)
        {
            if (flatObjects == null)
            {
                return null;
            }

            List<RecursiveObject> recursiveObjects = new List<RecursiveObject>();

            foreach (var item in flatObjects ?? new List<CategoriaWebServiceAtributo>())
            {
                recursiveObjects.Add(new RecursiveObject
                {
                    data = item.Nome,
                    id = item.ID,
                    attr = new FlatTreeAttribute { id = item.ID.ToString(), selected = this.AtributoSelecionado(item.ID) },
                    children = FillRecursive(item.Childrens)
                });
            }

            return recursiveObjects;
        }

        private bool AtributoSelecionado(long id)
        {
            int categoriaWorkflowID = Convert.ToInt32(TempData["categoriaWorkflowID"]);
            CategoriaWorkflow categoriaworkflow = db.CategoriaWorkflow.Find(categoriaWorkflowID);

            if (categoriaworkflow == null)
            {
                return false;
            }

            return categoriaworkflow.CategoriaWebService.CategoriaWebServiceAtributos.Any(a => a.ID == id && !a.Childrens.Any());
        }

        public List<CategoriaWebServiceAtributo> RetornaPropriedadesSelecionadas(List<CategoriaWebServiceAtributo> propriedadesWebService, List<CategoriaWebServiceAtributo> propriedadesExistentes, List<string> idsSelecionados, int categoriaWorkflowID)
        {
            if (propriedadesWebService == null)
            {
                return null;
            }

            return (from p in propriedadesWebService
                    join j in propriedadesExistentes
                        on p.ID equals j.ID into lj
                    from e in lj.DefaultIfEmpty()
                    select new CategoriaWebServiceAtributo
                    {
                        ID = p.ID,
                        CategoriaWorkflowID = categoriaWorkflowID,
                        ParentID = p.ParentID,
                        Nome = p.Nome,
                        Apelido = (e != null ? e.Apelido : null),
                        Ordem = (e != null ? e.Ordem : null),
                        IsPrimaryKey = (e != null ? e.IsPrimaryKey : false),
                        Parent = p.Parent,
                        Childrens = RetornaPropriedadesSelecionadas(p.Childrens, propriedadesExistentes, idsSelecionados, categoriaWorkflowID)
                    })
                    .Where(p => idsSelecionados.Contains(p.ID.ToString()) ||
                                (p.Childrens != null && p.Childrens.Any()))
                    .ToList<CategoriaWebServiceAtributo>();
        }
    }
}
